﻿/*
 *  File: BitTools.cs
 * 
 * 
 *  Author: Aaron C. d. C (AKA Magnus or NinjiHaku)
 *  
 *  Date: 29/07/2013
 *  
 *  License: https://pkmndotnet.codeplex.com/license
 * 
 *  Description: Contains structures and classes with functions that help to work with bits and bytes.
 *  
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace PkMnDotNet
{
    /// <summary>
    /// Structure that represent a single BIT.
    /// </summary>
    public struct BIT
    {

        /*
         * This structure should not be needed. The purpose of this library
         * is to avoid the manipulation of bits and bytes as much as possible.
         * However, I decided to add it just in case.
         */

        internal bool bt;

        public bool Bit_
        {
            get { return bt; }
            set { bt = value; }
        }

        public BIT(bool val)
        {
            this.bt = val;
        }

        public void SET()
        {
            this.Bit_ = true;
        }

        public void SET(int value)
        {
            if (value >= 1)
                this.Bit_ = true;
            else if (value == 0)
                this.Bit_ = false;
        }

        public void CLEAR()
        {
            this.Bit_ = false;
        }

        public static implicit operator bool(BIT val)
        {
            return val.Bit_;
        }

        public static implicit operator int(BIT val)
        {
            if (val)
                return 1;
            else
                return 0;
        }

        public static implicit operator BIT(bool val)
        {
            BIT res = 0;
            if (val)
                res.SET();
            else
                res.CLEAR();
            return res;
        }

        public static implicit operator BIT(int val)
        {
            BIT res = 0;
            if (val >= 1)
                res.SET();
            else if (val == 0)
                res.CLEAR();
            return res;
        }

        public static implicit operator byte(BIT val)
        {
            if (val)
                return 1;
            else
                return 0;
        }

        public override string ToString()
        {
            return ((int)this).ToString();
        }
    }


    /// <summary>
    /// Represents a value of 16 unsigned bits (2 bytes)
    /// </summary>
    public struct WORD
    {
        //A WORD is represented in 2 bytes, high endian.
        internal byte hword, lword;

        /// <summary>
        /// Represent the major significant byte.
        /// </summary>
        public byte HIWORD
        {
            get { return hword; }
            set { hword = value; }
        }

        /// <summary>
        /// Represent the less significant byte
        /// </summary>
        public byte LOWORD
        {
            get { return lword; }
            set { lword = value; }
        }

        /// <summary>
        /// Cast a WORD into a 16 bit unsigned integer
        /// </summary>
        /// <param name="value">A WORD</param>
        /// <returns>An unsigned 16 bit integer</returns>
        public static implicit operator UInt16(WORD value)
        {
            return (UInt16)((UInt16)((value.HIWORD << 8) & 0xFF00) + (UInt16)(value.LOWORD));
        }

        /// <summary>
        /// Cast a 16 bit unsigned integer into a WORD
        /// </summary>
        /// <param name="value">An unsigned 16 bit integer</param>
        /// <returns>A WORD</returns>
        public static implicit operator WORD(UInt16 value)
        {
            return new WORD((byte)((value >> 8) & 0xFF), (byte)(value & 0xFF));
        }

        /// <summary>
        /// Cast a signed 32 bit integer into a WORD if possible. If not, it returns 0.
        /// </summary>
        /// <param name="value">A 32 integer value</param>
        /// <returns>A WORD</returns>
        public static implicit operator WORD(int value)
        {
            return (value <= 0xFFFF)?new WORD((byte)((value >> 8) & 0xFF), (byte)(value & 0xFF)):new WORD(0,0);
        }

        /// <summary>
        /// Cast a single byte into a WORD
        /// </summary>
        /// <param name="value">A Byte</param>
        /// <returns>A WORD</returns>
        public static implicit operator WORD(byte value)
        {
            return new WORD(0, value);
        }

        /// <summary>
        /// Cast a DWORD into a WORD if possible. If not, it returns 0.
        /// </summary>
        /// <param name="value">A DWORD</param>
        /// <returns>A WORD</returns>
        public static implicit operator WORD(DWORD value)
        {
            return (value.ToUnsignedInteger() <= 0xFFFF)?new WORD(value.LoWORD, value.LOWORD):new WORD(0,0);
        }

        /// <summary>
        /// Creates a new WORD
        /// </summary>
        /// <param name="HIvalue">The Major significant byte</param>
        /// <param name="LOvalue">The Less significant byte</param>
        public WORD(byte HIvalue, byte LOvalue)
        {
            hword = 0; lword = 0;
            LOWORD = LOvalue;
            HIWORD = HIvalue;
        }


        /// <summary>
        /// Returns an unisgned 16 bit integer containing the value of this WORD
        /// </summary>
        /// <returns>An unisgned 16 bit integer containing the value of this WORD</returns>
        public UInt16 ToUInt16()
        {
            UInt16 result = HIWORD;
            return (ushort)((result << 8) + LOWORD);
        }

        /// <summary>
        /// Returns the value of this WORD in a string.
        /// </summary>
        /// <returns>A string with the value of this WORD.</returns>
        public override string ToString()
        {
            UInt16 result = HIWORD;
            result = (ushort)((result << 8) + LOWORD);
            return result.ToString();
        }

        /* Operator overriders */

        // SUM
        public static WORD operator +(WORD c1, WORD c2)
        {
            return (WORD)(c1.ToUInt16() + c2.ToUInt16());
        }

        // INCREMENT
        public static WORD operator ++(WORD c1)
        {
            return (WORD)(c1.ToUInt16() + 1);
        }

        // SUBSTRACT
        public static WORD operator -(WORD c1, WORD c2)
        {
            return (WORD)(c1.ToUInt16() - c2.ToUInt16());
        }

        // DECREMENT
        public static WORD operator --(WORD c1)
        {
            return (WORD)(c1.ToUInt16() - 1);
        }

        // BIT INVERSION
        public static WORD operator ~(WORD c1)
        {
            return new WORD((byte)~c1.HIWORD, (byte)~c1.LOWORD);
        }

        // XOR
        public static WORD operator ^(WORD c1, WORD c2)
        {
            return new WORD((byte)(c1.HIWORD ^ c2.HIWORD), (byte)(c1.LOWORD ^ c2.LOWORD));
        }

        // AND
        public static WORD operator &(WORD c1, WORD c2)
        {
            return new WORD((byte)(c1.HIWORD & c2.HIWORD), (byte)(c1.LOWORD & c2.LOWORD));
        }

        // OR
        public static WORD operator |(WORD c1, WORD c2)
        {
            return new WORD((byte)(c1.HIWORD | c2.HIWORD), (byte)(c1.LOWORD | c2.LOWORD));
        }

        // BITWISE SHIFT
        public static WORD operator <<(WORD c1, int c2)
        {
            return (WORD)(c1.ToUInt16() << c2);
        }

        // COUNTER BITWISE SHIFT
        public static WORD operator >>(WORD c1, int c2)
        {
            return (WORD)(c1.ToUInt16() >> c2);
        }

        //Boolean operators
        public static bool operator ==(WORD c1, WORD c2)
        {
            return (c1.ToUInt16() == c2.ToUInt16());
        }

        public static bool operator !=(WORD c1, WORD c2)
        {
            return (c1.ToUInt16() != c2.ToUInt16());
        }

        public static bool operator >(WORD c1, WORD c2)
        {
            return (c1.ToUInt16() > c2.ToUInt16());
        }

        public static bool operator <(WORD c1, WORD c2)
        {
            return (c1.ToUInt16() < c2.ToUInt16());
        }

        public static bool operator >=(WORD c1, WORD c2)
        {
            return (c1.ToUInt16() >= c2.ToUInt16());
        }

        public static bool operator <=(WORD c1, WORD c2)
        {
            return (c1.ToUInt16() <= c2.ToUInt16());
        }

        public static bool operator ==(WORD c1, DWORD c2)
        {
            return (c1.ToUInt16() == c2.ToUnsignedInteger());
        }

        public static bool operator !=(WORD c1, DWORD c2)
        {
            return (c1.ToUInt16() != c2.ToUnsignedInteger());
        }

        public static bool operator >(WORD c1, DWORD c2)
        {
            return (c1.ToUInt16() > c2.ToUnsignedInteger());
        }

        public static bool operator <(WORD c1, DWORD c2)
        {
            return (c1.ToUInt16() < c2.ToUnsignedInteger());
        }

        public static bool operator >=(WORD c1, DWORD c2)
        {
            return (c1.ToUInt16() >= c2.ToUnsignedInteger());
        }

        public static bool operator <=(WORD c1, DWORD c2)
        {
            return (c1.ToUInt16() <= c2.ToUnsignedInteger());
        }

        public static bool operator ==(WORD c1, int c2)
        {
            return (c1.ToUInt16() == c2);
        }

        public static bool operator !=(WORD c1, int c2)
        {
            return (c1.ToUInt16() != c2);
        }

        public static bool operator >(WORD c1, int c2)
        {
            return (c1.ToUInt16() > c2);
        }

        public static bool operator <(WORD c1, int c2)
        {
            return (c1.ToUInt16() < c2);
        }

        public static bool operator >=(WORD c1, int c2)
        {
            return (c1.ToUInt16() >= c2);
        }

        public static bool operator <=(WORD c1, int c2)
        {
            return (c1.ToUInt16() <= c2);
        }
    }

    /// <summary>
    /// Represents a value of 32 unsigned bits (4 bytes)
    /// </summary>
    public struct DWORD
    {

        //A DWORD can be represented as 4 bytes

        byte hiword, hword, lword, loword;

        /// <summary>
        /// The major significant byte
        /// </summary>
        public byte HIWORD
        {
            get { return hiword; }
            set { hiword = value; }
        }
        /// <summary>
        /// The second major significant byte
        /// </summary>
        public byte HiWORD
        {
            get { return hword; }
            set { hword = value; }
        }
        /// <summary>
        /// The third major significant byte
        /// </summary>
        public byte LoWORD
        {
            get { return lword; }
            set { lword = value; }
        }
        /// <summary>
        /// The less significant byte
        /// </summary>
        public byte LOWORD
        {
            get { return loword; }
            set { loword = value; }
        }

        /// <summary>
        /// Creates a new DWORD
        /// </summary>
        /// <param name="HI">The major significant byte</param>
        /// <param name="Hi">The second major significant byte</param>
        /// <param name="Lo">The third major significant byte</param>
        /// <param name="LO">The less significant byte</param>
        public DWORD(byte HI, byte Hi, byte Lo, byte LO)
        {
            hiword = hword = lword = loword = 0;
            HIWORD = HI; HiWORD = Hi; LoWORD = Lo; LOWORD = LO;
        }

        public byte[] ToByteArray()
        {
            byte[] res = new byte[4];
            res[0] = this.HIWORD; res[1] = this.HiWORD;
            res[2] = this.LoWORD; res[3] = this.LOWORD;

            return res;
        }

        /// <summary>
        /// Returns an unsigned 32 bit integer containing the value of this DWORD.
        /// </summary>
        /// <returns>An unsigned 32 bit integer containing the value of this DWORD.</returns>
        public UInt32 ToUnsignedInteger()
        {
            UInt32 Res = ((UInt32)(this.HIWORD << 24)) + ((UInt32)(this.HiWORD << 16)) +
                ((UInt32)(this.LoWORD << 8)) + ((UInt32)this.LOWORD);
            return Res;
        }


        /// <summary>
        /// Cast a DWORD into a 32 bit unsigned integer
        /// </summary>
        /// <param name="value">The DWORD</param>
        /// <returns>An unsigned integer</returns>
        public static implicit operator uint(DWORD value)
        {
            return (uint)((value.HIWORD) << 24 + (value.HiWORD) << 16 + (value.LoWORD) << 8 + (value.LOWORD));
        }

        /// <summary>
        /// Cast a DWORD into a 32 bit signed integer
        /// </summary>
        /// <param name="value">The DWORD</param>
        /// <returns>An unsigned integer</returns>
        public static implicit operator int(DWORD value)
        {
            return ((value.HIWORD) << 24 + (value.HiWORD) << 16 + (value.LoWORD) << 8 + (value.LOWORD));
        }

        /// <summary>
        /// Cast a 32 bit signed integer into a DWORD
        /// </summary>
        /// <param name="value">An unsigned integer</param>
        /// <returns>A DWORD</returns>
        public static implicit operator DWORD(int value)
        {
            DWORD result = new DWORD(
                (byte)((value >> 24) & 0xFF),
                (byte)((value >> 16) & 0xFF),
                (byte)((value >> 8) & 0xFF),
                (byte)(value & 0xFF));
            return result;
        }

        /// <summary>
        /// Cast a 32 bit unsigned integer into a DWORD
        /// </summary>
        /// <param name="value">An unsigned integer</param>
        /// <returns>A DWORD</returns>
        public static implicit operator DWORD(uint value)
        {
            DWORD result = new DWORD(
                (byte)((value >> 24) & 0xFF),
                (byte)((value >> 16) & 0xFF),
                (byte)((value >> 8) & 0xFF),
                (byte)(value & 0xFF));
            return result;
        }

        /// <summary>
        /// Cast a WORD into a DWORD
        /// </summary>
        /// <param name="value">The WORD</param>
        /// <returns>A DWORD</returns>
        public static implicit operator DWORD(WORD value)
        {
            return new DWORD(0, 0, value.HIWORD, value.LOWORD);
        }

        /// <summary>
        /// Split the DWORD into 2 WORDS in big endian format
        /// </summary>
        /// <returns>An array of 2 WORD</returns>
        public WORD[] SplitIntoWords()
        {
            WORD[] Words = new WORD[2];
            Words[0].HIWORD = HIWORD; Words[0].LOWORD = HiWORD;
            Words[1].HIWORD = LoWORD; Words[1].LOWORD = LOWORD;
            return Words;
        }

        /// <summary>
        /// Returns the value of this DWORD in a string.
        /// </summary>
        /// <returns>The value of this DWORD, in a string.</returns>
        public override string ToString()
        {
            uint Res = this.ToUnsignedInteger();
            return Res.ToString();
        }

        /* OPERATOR OVERRIDERS */

        // SUM
        public static DWORD operator +(DWORD c1, DWORD c2)
        {
            return (DWORD)(c1.ToUnsignedInteger() + c2.ToUnsignedInteger());
        }

        // INCREMENT
        public static DWORD operator ++(DWORD c1)
        {
            return (DWORD)(c1.ToUnsignedInteger() + 1);
        }

        // DECREMENT
        public static DWORD operator --(DWORD c1)
        {
            return (DWORD)(c1.ToUnsignedInteger() - 1);
        }

        // SUBSTRACT
        public static DWORD operator -(DWORD c1, DWORD c2)
        {
            return (DWORD)(c1.ToUnsignedInteger() - c2.ToUnsignedInteger());
        }

        // XOR
        public static DWORD operator ^(DWORD c1, DWORD c2)
        {
            return new DWORD(
                (byte)(c1.HIWORD ^ c2.HIWORD),
                (byte)(c1.HiWORD ^ c2.HiWORD),
                (byte)(c1.LoWORD ^ c2.LoWORD),
                (byte)(c1.LOWORD ^ c2.LOWORD));
        }

        // AND
        public static DWORD operator &(DWORD c1, DWORD c2)
        {
            return new DWORD(
                (byte)(c1.HIWORD & c2.HIWORD),
                (byte)(c1.HiWORD & c2.HiWORD),
                (byte)(c1.LoWORD & c2.LoWORD),
                (byte)(c1.LOWORD & c2.LOWORD));
        }

        // OR
        public static DWORD operator |(DWORD c1, DWORD c2)
        {
            return new DWORD(
                (byte)(c1.HIWORD | c2.HIWORD),
                (byte)(c1.HiWORD | c2.HiWORD),
                (byte)(c1.LoWORD | c2.LoWORD),
                (byte)(c1.LOWORD | c2.LOWORD));
        }

        //BIT INVERSION
        public static DWORD operator ~(DWORD c1)
        {
            return new DWORD((byte)(~c1.HIWORD), (byte)(~c1.HiWORD), (byte)(~c1.LoWORD), (byte)(~c1.LOWORD));
        }

        //Boolean operators
        public static bool operator ==(DWORD c1, DWORD c2)
        {
            return (c1.ToUnsignedInteger() == c2.ToUnsignedInteger());
        }

        public static bool operator !=(DWORD c1, DWORD c2)
        {
            return (c1.ToUnsignedInteger() != c2.ToUnsignedInteger());
        }

        public static bool operator >(DWORD c1, DWORD c2)
        {
            return (c1.ToUnsignedInteger() > c2.ToUnsignedInteger());
        }

        public static bool operator <(DWORD c1, DWORD c2)
        {
            return (c1.ToUnsignedInteger() < c2.ToUnsignedInteger());
        }

        public static bool operator >=(DWORD c1, DWORD c2)
        {
            return (c1.ToUnsignedInteger() > c2.ToUnsignedInteger());
        }

        public static bool operator <=(DWORD c1, DWORD c2)
        {
            return (c1.ToUnsignedInteger() < c2.ToUnsignedInteger());
        }

        public static bool operator ==(DWORD c1, WORD c2)
        {
            return (c1.ToUnsignedInteger() == c2.ToUInt16());
        }

        public static bool operator !=(DWORD c1, WORD c2)
        {
            return (c1.ToUnsignedInteger() != c2.ToUInt16());
        }

        public static bool operator >(DWORD c1, WORD c2)
        {
            return (c1.ToUnsignedInteger() > c2.ToUInt16());
        }

        public static bool operator <(DWORD c1, WORD c2)
        {
            return (c1.ToUnsignedInteger() < c2.ToUInt16());
        }

        public static bool operator >=(DWORD c1, WORD c2)
        {
            return (c1.ToUnsignedInteger() >= c2.ToUInt16());
        }

        public static bool operator <=(DWORD c1, WORD c2)
        {
            return (c1.ToUnsignedInteger() <= c2.ToUInt16());
        }

        public static bool operator ==(DWORD c1, int c2)
        {
            return (c1.ToUnsignedInteger() == c2);
        }

        public static bool operator !=(DWORD c1, int c2)
        {
            return (c1.ToUnsignedInteger() != c2);
        }

        public static bool operator >(DWORD c1, int c2)
        {
            return (c1.ToUnsignedInteger() > c2);
        }

        public static bool operator <(DWORD c1, int c2)
        {
            return (c1.ToUnsignedInteger() < c2);
        }

        public static bool operator >=(DWORD c1, int c2)
        {
            return (c1.ToUnsignedInteger() >= c2);
        }

        public static bool operator <=(DWORD c1, int c2)
        {
            return (c1.ToUnsignedInteger() <= c2);
        }

        public static DWORD operator <<(DWORD c1, int c2)
        {
            return ((uint)c1 << c2);
        }

        public static DWORD operator >>(DWORD c1, int c2)
        {
            return ((uint)c1 >> c2);
        }
    }


    /// <summary>
    /// Class that contains functions to easily manipulate bits, nibbles and bytes.
    /// </summary>
    public class BitTools
    {

        /// <summary>
        /// Fill a bit string with zeros in the MSB, until it reach 4 bits.
        /// </summary>
        /// <param name="bits">A string that resemble an uncomplete nibble</param>
        /// <returns>A string that resemble a complete nibble (4 bits)</returns>
        public static string FillNibble(string bits)
        {
            if (bits.Length < 4)
            {
                string swap = bits, tempx = "";
                for (int x = 0; x < 4 - bits.Length; x++)
                {
                    tempx += "0";
                }
                tempx += swap;
                bits = tempx;
            }
            return bits;
        }

        /// <summary>
        /// Fill a bit string with zeros in the MSB, until it reach 8 bits.
        /// </summary>
        /// <param name="binary">A string that resemble a byte, in binary</param>
        /// <returns>A string that resemble a full byte, in binary (8 bit)</returns>
        public static string FillByte(string binary)
        {
            //This is probably not the best way to do this, but it works.
            //First, we fill the binary string, with zeros in the MSB, until it has 8 bits.
            if (binary.Length < 8)
            {
                string swap = binary, tempx = ""; //Lots of temporary variables that fills with garbage the memory. It works anyway.
                for (int x = 0; x < 8 - binary.Length; x++)
                {
                    tempx += "0";
                }
                tempx += swap;
                binary = tempx;
            }
            return binary;
        }

        /// <summary>
        /// Split a byte, into two bytes that resemble a Nibble, in big endian format.
        /// The maximum decimal value for a nibble (4 bits) is 15 (0x0F).
        /// </summary>
        /// <param name="b">The byte to be split.</param>
        /// <returns>A byte array, that contains 2 bytes with the values of the nibbles in b, in big endian format.</returns>
        public static byte[] SplitIntoNibbles(byte b)
        {
            byte[] nibbles = new byte[2];

            nibbles[1] = (byte)(((b << 4) >> 4) & 0x0F);
            nibbles[0] = (byte)(b >> 4);

            //We return each nibble.
            return nibbles;
        }

        /// <summary>
        /// Transform an array of 2 exact bytes into a single byte, in big endian format.
        /// </summary>
        /// <param name="nibbles">An array of 2 exact bytes.</param>
        /// <returns>The result, in a single byte.</returns>
        public static byte MergeNibbles(byte[] nibbles)
        {
            return (byte)((nibbles[0] << 4) | nibbles[1]);
        }


        /// <summary>
        /// Manually write bytes in the given offset. Returns true if success
        /// </summary>
        /// <param name="offset">The offset address to write</param>
        /// <param name="_byte">The byte to write in the given address</param>
        /// <param name="fs">A file stream that points to the save file</param>
        /// <returns>Returns TRUE if it succeed.</returns>
        public static bool WriteByte(int offset, byte _byte, FileStream fs)
        {
            try
            {
                fs.Seek(offset, SeekOrigin.Begin);
                fs.WriteByte(_byte);
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }

        /// <summary>
        /// Manually write bytes in the giving offset. Returns true if success.
        /// </summary>
        /// <param name="offset">The starting offset to write in.</param>
        /// <param name="_byte">The secuence of bytes to write, starting in the given offset.</param>
        /// <param name="fs">A file stream that points to the save file</param>
        /// <returns>Returns true if success</returns>
        public static bool WriteByte(int offset, byte[] _byte, FileStream fs)
        {
            try
            {
                fs.Seek(offset, SeekOrigin.Begin);
                foreach (byte b in _byte)
                {
                    fs.WriteByte(b);
                }
            }
            catch (Exception e)
            {
                return false;
            }
            return true;
        }


        /// <summary>
        /// Read a byte in the given offset.
        /// </summary>
        /// <param name="offset">The offset of the byte to retrieve.</param>
        /// <param name="fs">A file stream that points to the save file</param>
        /// <returns>A byte from the specified offset.</returns>
        public static byte ReadByte(int offset, FileStream fs)
        {
            byte result = 0x00;

                fs.Seek(offset, SeekOrigin.Begin);
                result = (byte)fs.ReadByte();
            return result;
        }

        /// <summary>
        /// Read a sucession of bytes, starting from the given offset.
        /// </summary>
        /// <param name="offset">The offset of the first byte.</param>
        /// <param name="length">The number of bytes to read from the offset.</param>
        /// <param name="fs">A file stream that points to the save file</param>
        /// <returns>An array of bytes from the specified offset, and determined length.</returns>
        public static byte[] ReadByte(int offset, int length, FileStream fs)
        {
            byte[] result = new byte[length];

            try
            {
                fs.Seek(offset, SeekOrigin.Begin);
                for (int x = 0; x < length; x++)
                {
                    result[x] = (byte)fs.ReadByte();
                }
            }
            catch (Exception e)
            {
                return null;
            }
            return result;
        }

        /// <summary>
        /// Get the positive decimal value of a sucession of bytes.
        /// </summary>
        /// <param name="values">The sucession of bytes. Must be Big endian format.</param>
        /// <returns>An unsigned integer representing the value of the bytes.</returns>
        public static uint BytesToInteger(byte[] values)
        {
            if (values.Length < 4)
            {
                byte[] swap = values;
                values = new byte[4];
                for (int x = 0; x < 4 - (swap.Length); x++)
                {
                    values[x] = 0x0;
                }
                Array.Copy(swap, values, swap.Length);
            }
            return BitConverter.ToUInt32(values, 0);
        }

        /// <summary>
        /// Process a 32 bit integer, and returns an array of bytes with the value of the number,
        /// in Big endian format (MSB->lsb).
        /// </summary>
        /// <param name="value">The number we want to process.</param>
        /// <returns>An array of bytes, whose length is the required amount of bytes to represent the given value.</returns>
        public static byte[] IntegerToBytes(UInt32 value)
        {
            int ReqBytes = 1;
            byte[] result, swap;

            //First, we determine the quantity of bytes required to represent the number.
            if (value < Math.Pow(2, 8))
                ReqBytes = 1;

            if (value >= Math.Pow(2, 8) && value < Math.Pow(2, 16))
                ReqBytes = 2;

            if (value >= Math.Pow(2, 16) && value < Math.Pow(2, 24))
                ReqBytes = 3;

            if (value >= Math.Pow(2, 24) && value < Math.Pow(2, 32))
                ReqBytes = 4;

            //Get the bytes. The bit converter gives you 4 bytes.

            result = BitConverter.GetBytes(value);
            Array.Reverse(result); //Reverse the endianess

            //We trim the quantity of bytes, if needed
            if (ReqBytes < 4)
            {
                swap = result;
                result = new byte[ReqBytes];

                for (int x = 0; x < ReqBytes; x++)
                {
                    result[x] = swap[swap.Length - 1 - x];
                }
                //We reversed the endianess again, so we re-reverse it again
                //Array.Reverse(result);
            }
            return result;
        }

        /// <summary>
        /// Get a bit from an integer
        /// </summary>
        /// <param name="index">The index of the bit to retrieve</param>
        /// <param name="value">A signed 32 bit integer</param>
        /// <returns>The desired BIT at index</returns>
        public static BIT GetBit(int index, int value)
        {
            BIT res = 0;
            byte[] bs_ = ((DWORD)value).ToByteArray();

            return ((bs_[index >> 3] & (1 << index)) != 0);
        }

        /// <summary>
        /// Get a bit from a WORD
        /// </summary>
        /// <param name="index">The index of the bit to retrieve</param>
        /// <param name="value">An usigned 16 bit DWORD</param>
        /// <returns>The desired BIT at index</returns>
        public static BIT GetBit(int index, WORD value)
        {
            BIT res = 0;
            byte[] bs_ = ((DWORD)value).ToByteArray();

            return ((bs_[index >> 3] & (1 << index)) != 0);
        }

        /// <summary>
        /// Get a bit from a DWORD
        /// </summary>
        /// <param name="index">The index of the bit to retrieve</param>
        /// <param name="value">An usigned 32 bit DWORD</param>
        /// <returns>The desired BIT at index</returns>
        public static BIT GetBit(int index, DWORD value)
        {
            BIT res = 0;
            byte[] bs_ = value.ToByteArray();

            return ((bs_[index >> 3] & (1 << index)) != 0);
        }

        /// <summary>
        /// Set a bit in the index position of the given value.
        /// </summary>
        /// <param name="index">The index of the bit to set</param>
        /// <param name="set">The value to set. True for 1, false for 0</param>
        /// <param name="value">The value where the bit will be set</param>
        /// <returns>A new integer with the bit already set.</returns>
        public static int SetBit(int index, bool set, int value)
        {
            if (set)
                return value | (1 << index);
            else
                return value & ~(1 << index);
        }

        /// <summary>
        /// Set a bit in the index position of the given value.
        /// </summary>
        /// <param name="index">The index of the bit to set</param>
        /// <param name="set">The value to set. True for 1, false for 0</param>
        /// <param name="value">The value where the bit will be set</param>
        /// <returns>A new integer with the bit already set.</returns>
        public static int SetBit(int index, bool set, WORD value)
        {
            if (set)
                return value | (1 << index);
            else
                return value & ~(1 << index);
        }

        /// <summary>
        /// Set a bit in the index position of the given value.
        /// </summary>
        /// <param name="index">The index of the bit to set</param>
        /// <param name="set">The value to set. True for 1, false for 0</param>
        /// <param name="value">The value where the bit will be set</param>
        /// <returns>A new integer with the bit already set.</returns>
        public static int SetBit(int index, bool set, DWORD value)
        {
            if (set)
                return value | (1 << index);
            else
                return value & ~(1 << index);
        }

        }
}
